/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package comunicacao;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

/**
 * Classe que fornece disponibiliza metodos para estabelecer uma
 * conexao e para fazer alterações a um servidor ZooKeeper
 * 
 * @author Leonardo Lino Nº45340
 * @author Diogo Pires Nº40351
 */
public class GestorZooKeeper{

	private ZooKeeper zk;

	public ZooKeeper connect(String hosts, int timeout) throws IOException,
			InterruptedException {

		final CountDownLatch signal = new CountDownLatch(1);

		zk = new ZooKeeper(hosts, timeout, new Watcher() {

			@Override
			public void process(WatchedEvent event) {
				if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
					signal.countDown();
				}
			}
		});
		
		signal.await();
		return zk;
	}

	public boolean createZNode(String nodePath, CreateMode mode, byte[] data) {

		boolean result = true;
		
		String createdPath;
		try {
			createdPath = zk.create(nodePath, data,
					ZooDefs.Ids.OPEN_ACL_UNSAFE, mode);
			
			System.out.println("Created " + createdPath);
		} catch (KeeperException | InterruptedException e) {
			System.out.println("Error while creating Group");
			e.printStackTrace();
			result = false;
		}

		return result;
	}

	public boolean joinGroup(String groupPath, String memberName, byte[] data) {
		boolean result = true;
		
		String path = groupPath + "/" + memberName;
		String createdPath;
		
		try {
			createdPath = zk.create(path, data,
					ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
			System.out.println("joined " + createdPath);
		} catch (KeeperException | InterruptedException e) {
			System.out.println("Error while joining group " + path);
			result = false;
		}

		return result;
	}

	public List<String> listGroup(String groupPath, Watcher watcher) {

		List<String> children = null;
		
		try {
			children = zk.getChildren(groupPath, watcher);
		} catch (KeeperException.NoNodeException e) {
			System.out.printf("Group %s does not exist \n", groupPath);
		} catch (KeeperException | InterruptedException e) {
		}
		
		return children;
	}
	
	public boolean setGroupWatcher(String groupPath, Watcher watcher) {
		boolean result = true;
		
		try {
			zk.getChildren(groupPath, watcher);
		} catch (KeeperException.NoNodeException e) {
			System.out.printf("Group %s does not exist \n", groupPath);
			result = false;
		} catch (InterruptedException | KeeperException e) {
			System.out.printf("Group %s does not exist \n", groupPath);
			result = false;
		}
		
		return result;
	}

	public Stat existsZNode(String groupPath, Watcher watcher) {
		Stat stat = null;

		try {
			stat = zk.exists(groupPath, watcher);
		} catch (KeeperException | InterruptedException e) {
			System.out.println("Error while verifiyng existence of group");
		}

		return stat;
	}

	public void deleteZNode(String groupPath) throws KeeperException,
			InterruptedException {

		try {
			List<String> children = zk.getChildren(groupPath, false);
			for (String child : children) {
				zk.delete(groupPath + "/" + child, -1);
			}
			zk.delete(groupPath, -1);
		} catch (KeeperException.NoNodeException e) {
			System.out.printf("Group %s does not exist \n", groupPath);
		}
	}
	
	public boolean setData(String nodePath, String data, int version){
		boolean result = true;
		
		try {
			zk.setData(nodePath, data.getBytes(), version);
		} catch (KeeperException | InterruptedException e) {
			System.out.println("Error setting data: " + nodePath);
			result = false;
		}
		
		return result;
	}
	
	public String getData(String nodePath, int version, Watcher watcher){
		Stat stat = new Stat();
		byte[] data = null;
		String strData = null;
		
		try {
			data = zk.getData(nodePath, watcher, stat);
			strData = new String(data);
		} catch (KeeperException | InterruptedException e) {
			System.out.println("Error getting data: " + nodePath);
		} catch (NullPointerException e) {
			System.out.println("Error getting data \"Null Pointer\": " + nodePath);
		}
		
		return strData;
	}

}
